﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace WFL.Threading
{
    public class BatchThread
    {
        private Thread _thread;

        public int Id
        {
            get
            {
                Thread thread = _thread;
                if (thread == null)
                {
                    return 0;
                }
                return thread.ManagedThreadId;
            }
        }

        public ThreadState State
        {
            get
            {
                Thread thread = _thread;
                if (thread == null)
                {
                    return ThreadState.Unstarted;
                }
                return thread.ThreadState;
            }
        }

        public BatchRuntime Runtime
        {
            get;
            internal set;
        }

        public BatchInstance BatchInstance
        {
            get;
            private set;
        }

        public BatchThread()
        {

        }

        internal void Execute(BatchInstance batchInstance)
        {
            if (batchInstance == null)
            {
                return;
            }
            if (batchInstance.Thread != null)
            {
                if (batchInstance.Thread == this)
                {
                    return;
                }
                throw new InvalidOperationException("指定任务实例已调度到其他线程中运行");
            }
            if (BatchInstance != null)
            {
                throw new InvalidOperationException("当前线程正在运行其他的任务实例");
            }
            BatchInstance = batchInstance;
            batchInstance.Thread = this;
            _thread = new Thread(OnExecute);
            _thread.IsBackground = true;
            _thread.Start();
        }

        internal void Cancel()
        {
            Thread thread = _thread;
            if (thread == null
                || thread.ThreadState == ThreadState.Unstarted
                || thread.ThreadState == ThreadState.AbortRequested
                || thread.ThreadState == ThreadState.Aborted
                || thread.ThreadState == ThreadState.StopRequested
                || thread.ThreadState == ThreadState.Stopped)
            {
                return;
            }
            try
            {
                thread.Abort(BatchInstance.CancelData);
                if (!thread.Join(20000))
                {
                    //记录线程等待超时（20秒）没有结束的异常情况
                    Runtime.OnLog("线程取消等待时间超过20s");
                }
            }
            catch (ThreadStateException)
            {
                //取消处于挂起的线程时会抛出该异常
                //取消行为将被延迟到线程恢复时
                //主动中断线程
                thread.Interrupt();
            }
        }

        private void OnExecute()
        {
            try
            {
                BatchInstance.State = BatchInstanceState.Executing;
                BatchInstance.StartTime = DateTime.Now;
                BatchInstance.Batch.InstanceStateChange(BatchInstance);
                BatchInstance.Batch.Execute(BatchInstance);
                BatchInstance.State = BatchInstanceState.Succeeded;
                BatchInstance.EndTime = DateTime.Now;
            }
            catch (ThreadAbortException)
            {
                //线程被取消
                BatchInstance.State = BatchInstanceState.Cancelled;
                BatchInstance.EndTime = DateTime.Now;
            }
            catch (ThreadInterruptedException)
            {
                //线程被中断
                BatchInstance.State = BatchInstanceState.Cancelled;
                BatchInstance.EndTime = DateTime.Now;
            }
            catch (Exception ex)
            {
                //业务逻辑发生异常
                BatchInstance.State = BatchInstanceState.Exception;
                BatchInstance.EndTime = DateTime.Now;
                BatchInstance.Exception = ex;
            }
            finally
            {
                try
                {
                    BatchInstance.Batch.InstanceStateChange(BatchInstance);
                }
                finally
                {
                    //调度下个排队任务实例
                    Runtime.ScheduleWaitingInstances(this);
                }
            }
        }
    }
}
